package com.xiaoyu.lib_av.datamodel

import `in`.srain.cube.request.JsonData
import `in`.srain.cube.util.StringUtil
import androidx.annotation.StringDef
import io.agora.rtm.LocalInvitation
import io.agora.rtm.RemoteInvitation
import java.io.Serializable

class CallParams(@param:CallTypeDef @field:CallTypeDef
                 val type: String, val channelId: String, val fromUser: CallUser, val toUser: CallUser, val payload: String = "") : Serializable {

    val isInvalid: Boolean
        get() = INVALID == this

    fun getFuser(isFromSelf: Boolean): CallUser {
        return if (isFromSelf) {
            toUser
        } else {
            fromUser
        }
    }

    fun getFuid(isFromSelf: Boolean): String {
        return getFuser(isFromSelf).uid
    }

    @StringDef(EMPTY, VOICE_CALL, VOICE_MATCH)
    annotation class CallTypeDef

    fun toJson(): JsonData {
        val jsonData = JsonData.newMap()
        jsonData.put("type", type)
        jsonData.put("channelId", channelId)
        jsonData.put("fromUser", fromUser.toJson())
        jsonData.put("toUser", toUser.toJson())
        jsonData.put("payload", JsonData.create(payload))
        return jsonData
    }

    override fun toString(): String {
        return "CallParams(type='$type', channelId='$channelId', fromUser=$fromUser, toUser=$toUser, payload='$payload')"
    }

    class CallUser private constructor(val uid: String, val token: String) : Serializable {

        val isNobody: Boolean
            get() = NOBODY == this

        fun toJson(): JsonData {
            val jsonData = JsonData.newMap()
            jsonData.put("uid", uid)
            jsonData.put("token", token)
            return jsonData
        }

        override fun toString(): String {
            return "CallUser(uid='$uid', token='$token')"
        }

        companion object {

            internal val NOBODY = CallUser("", "")

            fun fromJson(jsonData: JsonData): CallUser {
                val uid = jsonData.optString("uid")
                val token = jsonData.optString("token")
                return if (StringUtil.isAnyEmpty(uid, token)) NOBODY else CallUser(uid, token)
            }
        }
    }

    companion object {

        const val EMPTY = ""
        const val VOICE_CALL = "voiceCall"
        const val VIDEO_CALL = "videoCall"
        const val VOICE_MATCH = "voiceMatch"
        const val VIDEO_MATCH = "videoMatch"

        val INVALID = CallParams(EMPTY, "", CallUser.NOBODY, CallUser.NOBODY)

        private fun fromInvitationContent(content: String): CallParams {
            return fromJson(JsonData.create(content))
        }

        fun fromLocalInvitation(localInvitation: LocalInvitation): CallParams {
            return fromInvitationContent(localInvitation.content)
        }

        fun fromRemoteInvitation(remoteInvitation: RemoteInvitation): CallParams {
            return fromInvitationContent(remoteInvitation.content)
        }

        fun fromJson(jsonData: JsonData): CallParams {
            val type = jsonData.optString("type")
            val channelId = jsonData.optString("channelId")
            val fromUser = CallUser.fromJson(jsonData.optJson("fromUser"))
            val targetUser = CallUser.fromJson(jsonData.optJson("toUser"))
            val payload = jsonData.optJson("payload").toString()

            return if (StringUtil.isAnyEmpty(type, channelId)) INVALID else CallParams(type, channelId, fromUser, targetUser, payload)
        }
    }
}
